package com.stone.springboot.swagger;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.CollectionUtils;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.ApiSelector;
import springfox.documentation.spring.web.plugins.MyDocket;

import java.io.IOException;
import java.util.List;

/**
 * author : Stone
 * time : 2019/7/26 10:40
 */
@Slf4j
public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Swagger2Config swagger2Config;

    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public void setEnvironment(Environment environment) {
        String property = environment.getProperty("swagger2-config");
        try {
            if (null == property || property.length() == 0) return;
            swagger2Config = mapper.readValue(property, Swagger2Config.class);
        } catch (IOException e) {
            log.error("load swagger2 config error", e);
        }
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        if(null == swagger2Config || CollectionUtils.isEmpty(swagger2Config.getApiInfoList())) return;
        Contact contact = new Contact(swagger2Config.getContactUser(), swagger2Config.getContactUrl(), swagger2Config.getContactEmail());
        List<Swagger2Config.ApiInfo> apiInfoList = swagger2Config.getApiInfoList();
        for (int i = 0; i < apiInfoList.size(); i++) {
            Swagger2Config.ApiInfo e = apiInfoList.get(i);
            RootBeanDefinition definition = new RootBeanDefinition(MyDocket.class);
            ApiInfo apiInfo = apiInfo(e, contact);
            ApiSelector selector = selector(e);
            ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
            constructorArgumentValues.addGenericArgumentValue(DocumentationType.SWAGGER_2);
            constructorArgumentValues.addGenericArgumentValue(e.getName());
            constructorArgumentValues.addGenericArgumentValue(apiInfo);
            constructorArgumentValues.addGenericArgumentValue(selector);
            definition.setConstructorArgumentValues(constructorArgumentValues);
            registry.registerBeanDefinition("Docket" + System.currentTimeMillis() + i, definition);
        }

    }


    private ApiInfo apiInfo(Swagger2Config.ApiInfo info, Contact contact) {
        return new ApiInfoBuilder().title(info.getTitle())
                .termsOfServiceUrl(info.getTermsOfServiceUrl())
                .contact(contact)
                .version(info.getVersion())
                .build();
    }

    private ApiSelector selector(Swagger2Config.ApiInfo info) {
        return new ApiSelectorBuilder()
                .apis(RequestHandlerSelectors.basePackage(info.getPack()))
                .paths(PathSelectors.any()).build();
    }
}
